右击src建立新的文件夹:
建立相关的.c .h文件:
如下图:
此时像GPIO操作一样,如果有自定义头文件,则需要将文件目录添加到路径中,步骤如上,最后结果如下图:
x// init EEPROM deviceint eeprom_init(const char *i2c_dev) { int fd = open(i2c_dev, O_RDWR); if (fd < 0) { perror("Failed to open I2C bus"); return -1; }
if (ioctl(fd, I2C_SLAVE, EEPROM_ADDR) < 0) { perror("Failed to set I2C address"); close(fd); return -1; }
return fd;}
// Write data to EEPROMbool eeprom_write(int fd, unsigned short addr, const unsigned char *data, unsigned int len) { if (fd < 0 || data == NULL || len == 0) { return false; }
// Create a data buffer for writing unsigned char *buf = malloc(len + 2); if (buf == NULL) { perror("Memory allocation failed"); return false; }
// Set address (16-bit) buf[0] = (addr >> 8) & 0xFF; // High byte buf[1] = addr & 0xFF; // Low byte
// copy data memcpy(buf + 2, data, len);
// write data if (write(fd, buf, len + 2) != (len + 2)) { perror("EEPROM write failed"); free(buf); return false; }
free(buf); usleep(10000); // Wait for write completion return true;}
// Read data from EEPROMbool eeprom_read(int fd, unsigned short addr, unsigned char *data, unsigned int len) { if (fd < 0 || data == NULL || len == 0) { return false; }
// Set read address (16-bit) unsigned char addr_buf[2]; addr_buf[0] = (addr >> 8) & 0xFF; // High byte addr_buf[1] = addr & 0xFF; // Low byte
if (write(fd, addr_buf, 2) != 2) { perror("EEPROM set read address failed"); return false; }
// read data if (read(fd, data, len) != len) { perror("EEPROM read failed"); return false; }
return true;}
// Close EEPROM devicevoid eeprom_close(int fd) { if (fd >= 0) { close(fd); }}右击src建立新的文件夹:
建立相关的.c .h文件,如下图:
xxxxxxxxxx// init shtc3 sensor deviceint shtc3_init(const char *i2c_dev) { int fd = open(i2c_dev, O_RDWR); if (fd < 0) { perror("Failed to open I2C bus"); return -1; }
if (ioctl(fd, I2C_SLAVE, SHTC3_ADDR) < 0) { perror("Failed to open SHTC3 device"); close(fd); return -1; }
return fd;}
// Read data from SHTC3 sensorbool shtc3_read_data(int fd, shtc3_data_t *data) { unsigned char cmd[2]; unsigned char sensor_data[6];
if (fd < 0 || data == NULL) { return false; }
// Wake up sensor cmd[0] = (CMD_WAKEUP >> 8) & 0xFF; cmd[1] = CMD_WAKEUP & 0xFF; if (write(fd, cmd, 2) != 2) { perror("SHTC3 wakeup failed"); return false; } usleep(1000);
// Send measurement command cmd[0] = (CMD_MEASURE >> 8) & 0xFF; cmd[1] = CMD_MEASURE & 0xFF; if (write(fd, cmd, 2) != 2) { perror("SHTC3 measure command failed"); return false; } usleep(20000);
// Read 6 bytes of data if (read(fd, sensor_data, 6) != 6) { perror("Failed to read SHTC3 data"); return false; }
// Convert raw data uint16_t raw_temp = (sensor_data[0] << 8) | sensor_data[1]; uint16_t raw_hum = (sensor_data[3] << 8) | sensor_data[4];
// Calculate temperature and humidity data->temperature = -45 + 175 * ((float)raw_temp / 65535.0); data->humidity = 100 * ((float)raw_hum / 65535.0);
return true;}
// Close SHTC3 sensor devicevoid shtc3_close(int fd) { if (fd >= 0) { unsigned char cmd[2]; // Send sleep command cmd[0] = (CMD_SLEEP >> 8) & 0xFF; cmd[1] = CMD_SLEEP & 0xFF; write(fd, cmd, 2); close(fd); }}
右击src建立新的文件夹:
建立相关的.c .h文件,如下图:
xxxxxxxxxx// use PCF8563 RTC or PCF85063 RTC
unsigned char dec2bcd(int dec) { return ((dec / 10) << 4) | (dec % 10);}
uint8_t bcd2dec(uint8_t bcd) { return ((bcd >> 4) * 10) + (bcd & 0x0F);}
int open_rtc_dev(const char *i2c_dev){ uint8_t buf[2]; // Register address + 1 data byte uint8_t slave_addr = PCF85063_SLAVE_ADDR; // Default slave address for PCF85063 int fd = open(i2c_dev, O_RDWR); if (fd < 0) { perror("Failed to open I2C bus"); return -1; }
slave_addr = PCF8563_DEVICE_ADDR; // Use PCF8563 address if defined
if (ioctl(fd, I2C_SLAVE, slave_addr) < 0) { perror("Failed to set I2C address"); close(fd); return -1; }
unsigned char reg = 0x04; if (fd < 0) { return false; }
// reset PCF8563 buf[0] = PCF8563_REG_CONTROL_STATUS1; buf[1] = 0x00; if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; }
// disable PCF8563 alarm buf[0] = PCF8563_REG_CONTROL_STATUS2; buf[1] = 0x00; if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; }
// Disable clock output buf[0] = PCF8563_REG_CLKOUT_CONTROL; buf[1] = 0x00; if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; }
// disable timer buf[0] = PCF8563_REG_TIMER_CONTROL; buf[1] = 0x00; if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; } // reset PCF85063 buf[0] = PCF85063_REG_CONTROL1; buf[1] = 0x00; if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; }
// Disable the alarm function and timer interrupt buf[0] = PCF85063_REG_CONTROL2; buf[1] = 0x00; if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; }
// Disable clock output buf[0] = PCF85063_REG_TIMER_MODE; buf[1] = 0x00; if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; }
return fd;}
bool read_rtc(int fd, stDateTime *dt){ unsigned char reg = PCF85063_REG_SECONDS; // read from second register unsigned char data[7];
if (fd < 0 || dt == NULL) { return false; }
reg = PCF8563_REG_VL_SEC; // read from second register for PCF8563
// Set read start address (write 0x04 if (write(fd, ®, 1) != 1) { perror("set read register failed"); return false; }
// Read 7 bytes if (read(fd, data, 7) != 7) { perror("read rtc failed"); return false; }
dt->second = bcd2dec(data[0] & 0x7F); dt->minute = bcd2dec(data[1] & 0x7F); dt->hour = bcd2dec(data[2] & 0x3F); dt->day = bcd2dec(data[3] & 0x3F); dt->weekday = bcd2dec(data[4] & 0x07); dt->month = bcd2dec(data[5] & 0x1F); dt->year = bcd2dec(data[6]);
return true;}
bool set_rtc(int fd, const stDateTime *dt){ unsigned char reg = PCF85063_REG_SECONDS; if (fd < 0) { return false; }
reg = PCF8563_REG_VL_SEC; // read from second register for PCF8563
// Create a data buffer for writing uint8_t buf[8]; // Register header (1 byte) + 7-byte data field buf[0] = reg; // Starting register address for write buf[1] = dec2bcd(dt->second); buf[2] = dec2bcd(dt->minute); buf[3] = dec2bcd(dt->hour); buf[4] = dec2bcd(dt->day); buf[5] = dec2bcd(dt->weekday); buf[6] = dec2bcd(dt->month); buf[7] = dec2bcd(dt->year % 100);
// Write all data at once if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { perror("set_rtc write failed"); return false; }
return true;}
void close_rtc_dev(int fd){ if (fd >= 0) { close(fd); // Close the incoming file descriptor }}
打开/home/mind/petalinux_projects/petalinux-mind/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi,添加以下内容:
xxxxxxxxxx&i2c0 {
clock-frequency = <100000>; rtc@51{ compatible="nxp,pcf8563"; reg=<0x51>; };};修改完成之后保存退出,重新以下步骤:
xxxxxxxxxxpetalinux-buildpetalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --u-boot --fpga --force将工程目录images -> linux目录中的BOOT.BIN、boot.scr及image.ub复制到sd卡的FAT分区。文件系统不变。重启开发板
系统重启完成之后,查看/dev/目录下有没有一些 rtc 相关的设备文件,如下所示:
可以看到/dev 目录下有一个 rtc 和一个 rtc0 两个设备文件,但是其中 rtc 是 rtc0 的一个软链接文件,那么这个 rtc0 对应的就是我们的 pcf8563 设备,如果系统中没有注册(使用 Linux RTC 设备驱动框架)任何的 RTC 设备,那么在/dev 目录下是没有 rtc 相应的设备文件存在的;如果内核中注册了多个 RTC 设备,则会以 rtc0、rtc1、rtc2……的方式进行命名。 在/sys/class 目录下有一个 rtc 目录,该目录下文件如下所示:
这里的 rtc0 对应的就是 pcf8563 设备。
(1)查看时间:
使用 date 命令查看到的是系统时钟,并不是 RTC 时钟,系统时钟是系统启动之后由内核去维护的,并不是 RTC 硬件去维护的。可以使用hwclock 命令来查看 RTC 时钟
xxxxxxxxxxdatehwclock(2)设置 RTC 时间:
设置完成以后再次使用 date 命令查看一下当前时间就会发现时间改过来了
xxxxxxxxxxdate -s "2023-09-22 15:19:36"date(3)写入到 RTC 里面:
xxxxxxxxxxhwclock -w此时系统重启以后时间也不会丢失,如果开发板底板接了纽扣电池,那么开发板即使断电了时间也不会丢失。
xxxxxxxxxxroot@petalinux-mind:~# dateThu Aug 21 13:46:37 UTC 2025